package com.founder.tool.xml;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 *
 * <entity type="com.founder.entity.Order">
 *   <entityItem name="date">2012-02-01 00:00:00</entityItem>
 *   <entityItem name="name">Joe</entityItem>
 *   <entityItem name="status">
 *     <entity type="com.founder.entity.OrderStatus">
 *       <entityItem name="status">true</entityItem>
 *     </entity>
 *   </entityItem>
 *   <entityItem name="orderItems">
 *     <entityList>
 *       <entity type="com.founder.entity.OrderItem">
 *         <entityItem name="product">111</entityItem>
 *         <entityItem name="quantity">2</entityItem>
 *         <entityItem name="price">8.9</entityItem>
 *       </entity>
 *       <entity type="com.founder.entity.OrderItem">
 *         <entityItem name="product">112</entityItem>
 *         <entityItem name="quantity">22</entityItem>
 *         <entityItem name="price">8.92</entityItem>
 *       </entity>
 *     </entityList>
 *   </entityItem>
 *   <entityItem name="orderId">0</entityItem>
 * </entity>
 * 
 * <entityList>
 *   <entity type="com.founder.entity.OrderItem">
 *     <entityItem name="product">111</entityItem>
 *     <entityItem name="quantity">2</entityItem>
 *     <entityItem name="price">8.9</entityItem>
 *   </entity>
 *   <entity type="com.founder.entity.OrderItem">
 *     <entityItem name="product">112</entityItem>
 *     <entityItem name="quantity">22</entityItem>
 *     <entityItem name="price">8.92</entityItem>
 *   </entity>
 * </entityList>
 * 
 * 
 * @author chen_weihua
 *
 */
public class EntityHandler extends DefaultHandler {
	
	private LinkedList<Object> list = new LinkedList<Object>();
	
	private LinkedList<MyAttributes> attrList = new LinkedList<MyAttributes>();
	
	private StringBuffer value = new StringBuffer();
	
	private Object elementObject = null;
	
	public Object getResult() {
		return elementObject;
	}
	
	private MyAttributes initMyAttributes(Attributes attributes) {
		MyAttributes newAttributes = new MyAttributes();
		newAttributes.name = attributes.getValue(EntityTag.ENTITY_ATTR_NAME);
		newAttributes.type = attributes.getValue(EntityTag.ENTITY_ATTR_TYPE);
		return newAttributes;
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		
		//清空
		value.delete(0, value.length());
		
		MyAttributes myAttr = initMyAttributes(attributes);
		attrList.addFirst(myAttr);
		
		Object obj = null;
		if (EntityTag.ENTITY.equals(qName)
				|| EntityTag.ENTITY_LIST.equals(qName)) {
			
			if (EntityTag.ENTITY.equals(qName)) {
				String type = myAttr.type;
				obj = EntityMap.getEntity(type);
			}
			if (EntityTag.ENTITY_LIST.equals(qName)) {
				obj = new ArrayList();
			}
			if (list.size() > 0) {
				Object parent = list.get(0);
				if (parent != null) {
					if (parent instanceof Collection) {
						((Collection) parent).add(obj);
					} else {
						//setFieldValue(parent, name, obj);
					}
				}
			}
			list.addFirst(obj);
		}
	}

	@Override
	public void characters(char[] ch, int start, int length)
			throws SAXException {
		if (length > 0) {
			value.append(ch, start, length);
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		MyAttributes myAttr = attrList.removeFirst();
		if (EntityTag.ENTITY_ITEM.equals(qName)) {
			Object obj = list.get(0);
			String name = myAttr.name;
			
			if (obj != null) {
				if (obj instanceof Collection) {
					/*
					if (value.length() == 0) {
						((Collection) obj).add(elementObject);
					} else {
						((Collection) obj).add(value.toString());
					}
					*/
				} else {
					if (value.length() == 0) {
						setFieldValue(obj, name, elementObject);
					} else {
						setFieldValue(obj, name, value.toString());
					}
				}
			}
		}
		
		if (EntityTag.ENTITY.equals(qName)
				|| EntityTag.ENTITY_LIST.equals(qName)) {
			elementObject = list.removeFirst();
		}
		//清空
		value.delete(0, value.length());
	}
	
	@SuppressWarnings("unchecked")
	private void setFieldValue(Object bean, String fieldName, Object value) {
		//System.out.println("bean=" + bean + ", fieldName=" + fieldName + ", value=" + value);
        try {
    		Class<?> cls = bean.getClass();
    		Field field = cls.getDeclaredField(fieldName);
    		Class<?> type = field.getType();
    		Method fieldSetMet = cls.getMethod(StringUtil.parSetName(fieldName), type);
    		if (type.isArray()) {
    			List collection = (List)value;
    			int length = collection.size();
    			if (length > 0) {
    				Object array = Array.newInstance(collection.get(0).getClass(), length);
    				for (int index = 0; index < length; index++) {
    					Array.set(array, index, collection.get(index));
    				}
    				fieldSetMet.invoke(bean, array);
    			} else {
    				fieldSetMet.invoke(bean, new Object[]{});
    			}
    		} else {
    			fieldSetMet.invoke(bean, value);
    		}
        } catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private void setFieldValue(Object bean, String fieldName, String value) {
		//System.out.println("bean=" + bean + ", fieldName=" + fieldName + ", value=" + value);
        try {
			Class<?> cls = bean.getClass();
			Field field = cls.getDeclaredField(fieldName);
			Class<?> type = field.getType();
			Method fieldSetMet = cls.getMethod(StringUtil.parSetName(fieldName), type);
			String fieldType = type.getSimpleName();
			if ("String".equals(fieldType)) {  
			    fieldSetMet.invoke(bean, value);  
			} else if ("Date".equals(fieldType)) {  
			    Date temp = StringUtil.parseDate(value);  
			    fieldSetMet.invoke(bean, temp);  
			} else if ("Integer".equals(fieldType)
			        || "int".equals(fieldType)) {  
			    Integer intval = Integer.parseInt(value);  
			    fieldSetMet.invoke(bean, intval);  
			} else if ("Long".equalsIgnoreCase(fieldType)) {  
			    Long temp = Long.parseLong(value);  
			    fieldSetMet.invoke(bean, temp);  
			} else if ("Double".equalsIgnoreCase(fieldType)) {  
			    Double temp = Double.parseDouble(value);  
			    fieldSetMet.invoke(bean, temp);  
			} else if ("Boolean".equalsIgnoreCase(fieldType)) {  
			    Boolean temp = Boolean.parseBoolean(value);  
			    fieldSetMet.invoke(bean, temp);  
			} else if ("Byte".equalsIgnoreCase(fieldType)) {  
				Byte temp = Byte.parseByte(value);
			    fieldSetMet.invoke(bean, temp);  
			} else if ("Short".equalsIgnoreCase(fieldType)) {  
				Short temp = Short.parseShort(value);
			    fieldSetMet.invoke(bean, temp);  
			} else if ("Character".equals(fieldType)
			        || "char".equals(fieldType)) {
				Character temp = value.charAt(0);  
			    fieldSetMet.invoke(bean, temp);
			} else {  
			    System.out.println("not supper type" + fieldType);  
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	class MyAttributes {
		String name;
		String type;
	}
}
